/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "libzlang_file.h"

ZlangInvokeFunction ZlangInvokeFunction_path_GetCurrentPath;
int ZlangInvokeFunction_path_GetCurrentPath( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_path	*path_direct_prop = GetObjectDirectProperty(obj) ;
	
	memset( path_direct_prop->pathname , 0x00 , sizeof(path_direct_prop->pathname) );
	getcwd( path_direct_prop->pathname , sizeof(path_direct_prop->pathname)-1 );
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "getcwd return[%s]" , path_direct_prop->pathname )
	path_direct_prop->pathname_len = strlen(path_direct_prop->pathname) ;
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_path_Path_string;
int ZlangInvokeFunction_path_Path_string( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_path	*path_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject		*in1 = GetInputParameterInLocalObjectStack(rt,1) ;
	struct ZlangObject		*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	char				*pathfilename = NULL ;
	int32_t				pathfilename_len ;
	
	CallRuntimeFunction_string_GetStringValue( rt , in1 , & pathfilename , & pathfilename_len );
	if( GetFileType(pathfilename) != FILE_TYPE_DIRECTORY )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "path[%s] invalid" , pathfilename )
		UnreferObject( rt , out1 );
		return 0;
	}
	if( pathfilename_len > sizeof(path_direct_prop->pathname)-1 )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "path[%"PRIi32"][%.*s] too long" , pathfilename_len , pathfilename_len,pathfilename )
		UnreferObject( rt , out1 );
		return 0;
	}
	
	memset( path_direct_prop->pathname , 0x00 , sizeof(path_direct_prop->pathname) );
	memcpy( path_direct_prop->pathname , pathfilename , pathfilename_len );
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "set path[%s]" , path_direct_prop->pathname )
	path_direct_prop->pathname_len = strlen(path_direct_prop->pathname) ;
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_path_ChangeParentPath;
int ZlangInvokeFunction_path_ChangeParentPath( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_path	*path_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject		*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	char				*p1 = NULL ;
	char				*p0 = NULL ;
	size_t				len1 ;
	
	p1 = memrchr( path_direct_prop->pathname , DIRECTORY_SEPARATOR_CHAR , path_direct_prop->pathname_len ) ;
	if( p1 == NULL )
	{
		CallRuntimeFunction_bool_SetBoolValue( rt , out1 , FALSE );
		return 0;
	}
	len1 = path_direct_prop->pathname+path_direct_prop->pathname_len - p1 ;
	
	p0 = memrchr( path_direct_prop->pathname , DIRECTORY_SEPARATOR_CHAR , p1-path_direct_prop->pathname ) ;
	if( p0 == NULL )
	{
		CallRuntimeFunction_bool_SetBoolValue( rt , out1 , FALSE );
		return 0;
	}
	
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "path[%.*s]" , (int)(path_direct_prop->pathname_len),path_direct_prop->pathname )
	*(p1) = '\0' ;
	path_direct_prop->pathname_len -= len1 ;
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "change parent path[%.*s]" , (int)(path_direct_prop->pathname_len),path_direct_prop->pathname )
	
	CallRuntimeFunction_bool_SetBoolValue( rt , out1 , TRUE );
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_path_ChangeChildPath_string;
int ZlangInvokeFunction_path_ChangeChildPath_string( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_path	*path_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject		*in1 = GetInputParameterInLocalObjectStack(rt,1) ;
	struct ZlangObject		*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	char				*child_directoryname = NULL ;
	int32_t				child_directoryname_len ;
	int32_t				len_bak ;
	
	CallRuntimeFunction_string_GetStringValue( rt , in1 , & child_directoryname , & child_directoryname_len );
	if( path_direct_prop->pathname_len + 1 + child_directoryname_len > sizeof(path_direct_prop->pathname)-1 )
	{
		CallRuntimeFunction_bool_SetBoolValue( rt , out1 , FALSE );
		return 0;
	}
	
	len_bak = path_direct_prop->pathname_len ;
	
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "path[%.*s]" , (int)(path_direct_prop->pathname_len),path_direct_prop->pathname )
	*(path_direct_prop->pathname+path_direct_prop->pathname_len) = DIRECTORY_SEPARATOR_CHAR ;
	memcpy( path_direct_prop->pathname+path_direct_prop->pathname_len+1 , child_directoryname , child_directoryname_len );
	path_direct_prop->pathname_len += 1 + child_directoryname_len ;
	*(path_direct_prop->pathname+path_direct_prop->pathname_len) = '\0' ;
	
	if( GetFileType(path_direct_prop->pathname) != FILE_TYPE_DIRECTORY )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "change parent path[%.*s] failed" , (int)(path_direct_prop->pathname_len),path_direct_prop->pathname )
		path_direct_prop->pathname_len = len_bak ;
		*(path_direct_prop->pathname+path_direct_prop->pathname_len) = '\0' ;
		CallRuntimeFunction_bool_SetBoolValue( rt , out1 , FALSE );
		return 0;
	}
	else
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "change parent path[%.*s] ok" , (int)(path_direct_prop->pathname_len),path_direct_prop->pathname )
	}
	
	CallRuntimeFunction_bool_SetBoolValue( rt , out1 , TRUE );
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_path_GetPathname;
int ZlangInvokeFunction_path_GetPathname( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_path	*path_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject		*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	
	CallRuntimeFunction_string_SetStringValue( rt , out1 , path_direct_prop->pathname , path_direct_prop->pathname_len );
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_path_ReadFileList;
int ZlangInvokeFunction_path_ReadFiles( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_path	*path_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject		*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	DIR				*dp = NULL ;
	struct dirent			*dtp = NULL ;
	struct ZlangObject		*file0 = NULL ;
	struct ZlangObject		*file = NULL ;
	size_t				filename_len ;
	struct ZlangDirectProperty_file	*file_direct_prop = NULL ;
	int				nret = 0 ;
	
	file0 = QueryGlobalObjectByObjectName( rt , ZLANG_OBJECT_file ) ;
	if( file0 == NULL )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "QueryGlobalObjectByObjectName[%s] failed" , ZLANG_OBJECT_file )
		return GetRuntimeErrorNo(rt);
	}
	
	dp = opendir( path_direct_prop->pathname ) ;
	if( dp == NULL )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "opendir[%s] failed" , path_direct_prop->pathname )
		UnreferObject( rt , out1 );
		return 0;
	}
	
	for( ; ; )
	{
		dtp = readdir( dp ) ;
		if( dtp == NULL )
			break;
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "readdir[%s] ok" , path_direct_prop->pathname )
		
		if( STRCMP( dtp->d_name , == , "." ) || STRCMP( dtp->d_name , == , ".." ) )
			continue;
		
		filename_len = strlen(dtp->d_name) ;
		if( filename_len > sizeof(((struct ZlangDirectProperty_file *)0)->filename)-1 )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "filename[%zu][%.*s] too long" , filename_len , (int)filename_len,dtp->d_name )
			closedir( dp );
			UnreferObject( rt , out1 );
			return 0;
		}
		
		file = CloneObjectInTmpStack( rt , NULL , file0 ) ;
		if( file == NULL )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "CloneObjectInTmpStack failed" )
			closedir( dp );
			UnreferObject( rt , out1 );
			return GetRuntimeErrorNo(rt);
		}
		file_direct_prop = GetObjectDirectProperty(file) ;
		memcpy( file_direct_prop->pathname , path_direct_prop->pathname , path_direct_prop->pathname_len );
		file_direct_prop->pathname_len = path_direct_prop->pathname_len ;
		memcpy( file_direct_prop->filename , dtp->d_name , filename_len );
		file_direct_prop->filename_len = filename_len ;
		
		nret = CallRuntimeFunction_array_Append( rt , out1 , file , NULL ) ;
		if( nret )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "CallRuntimeFunction_array_Append failed" )
			closedir( dp );
			UnreferObject( rt , out1 );
			return nret;
		}
	}
	
	closedir( dp );
	
	return 0;
}

ZlangCreateDirectPropertyFunction ZlangCreateDirectProperty_path;
void *ZlangCreateDirectProperty_path( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_path	*path_prop = NULL ;
	
	path_prop = (struct ZlangDirectProperty_path *)ZLMALLOC( sizeof(struct ZlangDirectProperty_path) ) ;
	if( path_prop == NULL )
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_ALLOC , "alloc memory for entity" )
		return NULL;
	}
	memset( path_prop , 0x00 , sizeof(struct ZlangDirectProperty_path) );
	
	return path_prop;
}

ZlangDestroyDirectPropertyFunction ZlangDestroyDirectProperty_path;
void ZlangDestroyDirectProperty_path( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_path	*path_direct_prop = GetObjectDirectProperty(obj) ;
	
	ZLFREE( path_direct_prop );
	
	return;
}

ZlangSummarizeDirectPropertySizeFunction ZlangSummarizeDirectPropertySize_path;
void ZlangSummarizeDirectPropertySize_path( struct ZlangRuntime *rt , struct ZlangObject *obj , size_t *summarized_obj_size , size_t *summarized_direct_prop_size )
{
	SUMMARIZE_SIZE( summarized_direct_prop_size , sizeof(struct ZlangDirectProperty_path) )
	return;
}

static struct ZlangDirectFunctions direct_funcs_path =
	{
		ZLANG_OBJECT_path , /* char *ancestor_name */
		
		ZlangCreateDirectProperty_path , /* ZlangCreateDirectPropertyFunction *create_entity_func */
		ZlangDestroyDirectProperty_path , /* ZlangDestroyDirectPropertyFunction *destroy_entity_func */
		
		NULL , /* ZlangFromCharPtrFunction *from_char_ptr_func */
		NULL , /* ZlangToStringFunction *to_string_func */
		NULL , /* ZlangFromDataPtrFunction *from_data_ptr_func */
		NULL , /* ZlangGetDataPtrFunction *get_data_ptr_func */
		
		NULL , /* ZlangOperatorFunction *oper_PLUS_func */
		NULL , /* ZlangOperatorFunction *oper_MINUS_func */
		NULL , /* ZlangOperatorFunction *oper_MUL_func */
		NULL , /* ZlangOperatorFunction *oper_DIV_func */
		NULL , /* ZlangOperatorFunction *oper_MOD_func */
		
		NULL , /* ZlangUnaryOperatorFunction *unaryoper_NEGATIVE_func */
		NULL , /* ZlangUnaryOperatorFunction *unaryoper_NOT_func */
		NULL , /* ZlangUnaryOperatorFunction *unaryoper_BIT_REVERSE_func */
		NULL , /* ZlangUnaryOperatorFunction *unaryoper_PLUS_PLUS_func */
		NULL , /* ZlangUnaryOperatorFunction *unaryoper_MINUS_MINUS_func */
		
		NULL , /* ZlangCompareFunction *comp_EGUAL_func */
		NULL , /* ZlangCompareFunction *comp_NOTEGUAL_func */
		NULL , /* ZlangCompareFunction *comp_LT_func */
		NULL , /* ZlangCompareFunction *comp_LE_func */
		NULL , /* ZlangCompareFunction *comp_GT_func */
		NULL , /* ZlangCompareFunction *comp_GE_func */
		
		NULL , /* ZlangLogicFunction *logic_AND_func */
		NULL , /* ZlangLogicFunction *logic_OR_func */
		
		NULL , /* ZlangLogicFunction *bit_AND_func */
		NULL , /* ZlangLogicFunction *bit_XOR_func */
		NULL , /* ZlangLogicFunction *bit_OR_func */
		NULL , /* ZlangLogicFunction *bit_MOVELEFT_func */
		NULL , /* ZlangLogicFunction *bit_MOVERIGHT_func */
		
		ZlangSummarizeDirectPropertySize_path , /* ZlangSummarizeDirectPropertySizeFunction *summarize_direct_prop_size_func */
	} ;

ZlangImportObjectFunction ZlangImportObject_path;
struct ZlangObject *ZlangImportObject_path( struct ZlangRuntime *rt )
{
	struct ZlangObject	*obj = NULL ;
	struct ZlangFunction	*func = NULL ;
	int			nret = 0 ;
	
	nret = ImportObject( rt , & obj , ZLANG_OBJECT_path , & direct_funcs_path , sizeof(struct ZlangDirectFunctions) , NULL ) ;
	if( nret )
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_LINK_FUNC_TO_ENTITY , "import object to global objects heap" )
		return NULL;
	}
	
	/* path.GetCurrentPath() */
	func = AddFunctionAndParametersInObject( rt , obj , "GetCurrentPath" , "GetCurrentPath()" , ZlangInvokeFunction_path_GetCurrentPath , ZLANG_OBJECT_void , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* path.Path(string) */
	func = AddFunctionAndParametersInObject( rt , obj , "Path" , "Path(string)" , ZlangInvokeFunction_path_Path_string , ZLANG_OBJECT_path , ZLANG_OBJECT_string,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* path.ChangeParentPath() */
	func = AddFunctionAndParametersInObject( rt , obj , "ChangeParentPath" , "ChangeParentPath()" , ZlangInvokeFunction_path_ChangeParentPath , ZLANG_OBJECT_bool , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* path.ChangeChildPath(file) */
	func = AddFunctionAndParametersInObject( rt , obj , "ChangeChildPath" , "ChangeChildPath(string)" , ZlangInvokeFunction_path_ChangeChildPath_string , ZLANG_OBJECT_bool , ZLANG_OBJECT_file,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* path.GetPathname() */
	func = AddFunctionAndParametersInObject( rt , obj , "GetPathname" , "GetPathname()" , ZlangInvokeFunction_path_GetPathname , ZLANG_OBJECT_string , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* path.ReadFiles() */
	func = AddFunctionAndParametersInObject( rt , obj , "ReadFiles" , "ReadFiles()" , ZlangInvokeFunction_path_ReadFiles , ZLANG_OBJECT_array , NULL ) ;
	if( func == NULL )
		return NULL;
	
	return obj ;
}

